/*
 * Copyright (c) 2008, Xiong Yingfei, the University of Tokyo
 * All rights reserved.
 */
package ac.jp.u_tokyo.SyncLib.tests;

import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertTrue;

import java.util.HashMap;
import java.util.Map;

import org.antlr.runtime.RecognitionException;
import org.junit.Before;
import org.junit.Test;

import ac.jp.u_tokyo.SyncLib.IDSync;
import ac.jp.u_tokyo.SyncLib.Mod;
import ac.jp.u_tokyo.SyncLib.NullMod;
import ac.jp.u_tokyo.SyncLib.Sync;
import ac.jp.u_tokyo.SyncLib.SyncFactory;
import ac.jp.u_tokyo.SyncLib.SynchronizationFailedException;
import ac.jp.u_tokyo.SyncLib.dictionaries.EqualDictMapCombinator;
import ac.jp.u_tokyo.SyncLib.modParser.ModParser;


public class EqualDictMapCombinatorTest extends SyncTestBase
{
	Sync _sync;
	
	@Before
	public void setUp() throws SynchronizationFailedException {
		_sync = new EqualDictMapCombinator(new SyncFactory() {

			public Sync create()
			{
				return new IDSync(true);
			}
			
		}, 2, 0);
		_sync.resynchronize(new Object[] { new HashMap(0), new HashMap(0)}, new Mod[] {NullMod.INSTANCE, NullMod.INSTANCE});

	}
	
	@Test
	public void testUnmatched() throws SynchronizationFailedException, RecognitionException {
		Mod[] result = checkedSynchronize(_sync, ModParser.parse("{1->a}, {2->b}"));
		assertArrayEquals(ModParser.parse("{1->a, 2->b}, {1->a, 2->b}"), result);
	}

	@Test
	public void testMatchOnePair() throws SynchronizationFailedException, RecognitionException {
		Mod[] result = checkedSynchronize(_sync, ModParser.parse("{1->a}, {1->a}"));
		assertArrayEquals(ModParser.parse("{1->a}, {1->a}"), result);
	}

	@Test
	public void testMatchTwoPair() throws SynchronizationFailedException, RecognitionException {
		Mod[] result = checkedSynchronize(_sync, ModParser.parse("{1->a, 3->b}, {1->a, 5->b}"));
		assertArrayEquals(ModParser.parse("{1->a, 3->b, 5->b}, {1->a, 3->b, 5->b}"), result);
	}
	
	@Test
	public void testMatchTwoPairResync() throws SynchronizationFailedException, RecognitionException {
		Map<Integer, String> dict1 = new HashMap<Integer, String>();
		dict1.put(1, "a");
		dict1.put(3, "b");
		Map<Integer, String> dict2 = new HashMap<Integer, String>();
		dict2.put(1, "a");
		dict2.put(5, "b");
		Mod[] result = checkedResynchronize(_sync, new Object[] {dict1, dict2},  ModParser.parse("nomod, {1->a, 5->b}"));
		assertArrayEquals(ModParser.parse("{1->a, 3->b, 5->b}, {1->a, 3->b, 5->b}"), result);
	}

	public void testMatchTwoPairResyncWithNoMod() throws SynchronizationFailedException, RecognitionException {
		Map<Integer, String> dict1 = new HashMap<Integer, String>();
		dict1.put(1, "a");
		dict1.put(3, "b");
		Map<Integer, String> dict2 = new HashMap<Integer, String>();
		dict2.put(1, "a");
		dict2.put(5, "b");
		Mod[] result = checkedResynchronize(_sync, new Object[] {dict1, dict2},  ModParser.parse("nomod, nomod"));
		assertTrue(((HashMap) result[0].apply(dict1)).keySet().size() == 3);
		assertTrue(((HashMap) result[0].apply(dict1)).keySet().contains(1));
		assertTrue(((HashMap) result[0].apply(dict1)).keySet().contains(5));
		assertTrue(((HashMap) result[0].apply(dict1)).keySet().contains(3));
		assertTrue(((HashMap) result[1].apply(dict2)).keySet().size() == 3);
		assertTrue(((HashMap) result[1].apply(dict2)).keySet().contains(2));
		assertTrue(((HashMap) result[1].apply(dict2)).keySet().contains(3));
		assertTrue(((HashMap) result[1].apply(dict2)).keySet().contains(5));
	}

	@Test
	public void testAdd() throws SynchronizationFailedException, RecognitionException {
		Mod[] result = checkedSynchronize(_sync, ModParser.parse("{1->a, 3->b}, {1->a}"));
		assertArrayEquals(ModParser.parse("{1->a, 3->b}, {1->a, 3->b}"), result);
	}

	@Test
	public void testRemove() throws SynchronizationFailedException, RecognitionException {
		Mod[] result = checkedSynchronize(_sync, ModParser.parse("{1->a, 5->b}, {1->a, 5->b}"));
		result = checkedSynchronize(_sync, ModParser.parse("{1->null}, nomod"));
		assertArrayEquals(ModParser.parse("{1->null}, {1->null}"), result);
	}

	@Test
	public void testModifyAfterRemove() throws SynchronizationFailedException, RecognitionException {
		Mod[] result = checkedSynchronize(_sync, ModParser.parse("{1->a, 5->b}, {1->a, 5->b}"));
		result = checkedSynchronize(_sync, ModParser.parse("{1->null}, nomod"));
		assertArrayEquals(ModParser.parse("{1->null}, {1->null}"), result);
		result = checkedSynchronize(_sync, ModParser.parse("{1->c}, nomod"));
		assertArrayEquals(ModParser.parse("{1->c}, {1->c}"), result);
	}
	
	@Test
	public void testModify() throws SynchronizationFailedException, RecognitionException {
		Mod[] result = checkedSynchronize(_sync, ModParser.parse("{1->a, 5->b}, {1->a, 5->b}"));
		result = checkedSynchronize(_sync, ModParser.parse("{1->c}, nomod"));
		assertArrayEquals(ModParser.parse("{1->c}, {1->c}"), result);
	}

	
	@Test
	public void testRevert() throws SynchronizationFailedException, RecognitionException {
		Mod[] result = checkedSynchronize(_sync, ModParser.parse("{1->a, 5->b}, {1->a, 5->b}"));
		_sync.setRevertPoint();
		result = checkedSynchronize(_sync, ModParser.parse("{1->null}, nomod"));
		_sync.revert();
		result = checkedSynchronize(_sync, ModParser.parse("nomod, {1->c}"));
		assertArrayEquals(ModParser.parse("{1->c}, {1->c}"), result);
	}
}
